package com.sailor.interceptor;

import com.sailor.annotation.SensitiveData;
import com.sailor.util.EncryptUtil;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author: sailor
 * @Description:
 */
@Component
@Intercepts({
        @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),
})
public class EncryptInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // @Signature 指定了 type= parameterHandler 后，这里的 invocation.getTarget() 便是parameterHandler
        // 若指定ResultSetHandler ，这里则能强转为ResultSetHandler
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
        // 获取参数对像，即 mapper 中 paramsType 的实例
        Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
        parameterField.setAccessible(true);
        // 取出实例
        Object parameterObject = parameterField.get(parameterHandler);
        if (parameterObject != null) {
            if (parameterObject instanceof HashMap) {
                Map<Object, Object> parameterMap = (HashMap) parameterObject;
                Set<Object> uniqueValues = parameterMap.values().stream().collect(Collectors.toSet());
                for (Object o : uniqueValues) {
                    processSensitiveData(o);
                }
            } else {
                processSensitiveData(parameterObject);
            }
        }
        return invocation.proceed();
    }

    private void processSensitiveData(Object object) throws IllegalAccessException {
        if (object != null) {
            Class<?> parameterObjectClass = object.getClass();
            // 校验该实例的类是否被@SensitiveData所注解
            SensitiveData sensitiveData = AnnotationUtils.findAnnotation(parameterObjectClass, SensitiveData.class);
            if (Objects.nonNull(sensitiveData)) {
                // 取出当前当前类所有字段，传入加密方法
                Field[] declaredFields = parameterObjectClass.getDeclaredFields();
                EncryptUtil.encrypt(declaredFields, object);
            }
        }
    }

    /**
     * 这个方法的作用是就是让mybatis判断，是否要进行拦截
     * 然后做出决定是否生成一个代理。
     */
    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    /**
     * 自定义配置写入，没有自定义配置的可以直接置空此方法
     **/
    @Override
    public void setProperties(Properties properties) {

    }
}
